package com.example.bankseckill.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.example.bankseckill.mapper.OrderMapper;
import com.example.bankseckill.pojo.*;
import com.example.bankseckill.pojo.vo.ProductVo;
import com.example.bankseckill.pojo.vo.RespPageBean;
import com.example.bankseckill.rabbitmq.MQsender;
import com.example.bankseckill.service.IOrderService;
import com.example.bankseckill.service.ISeckillOrderService;
import com.example.bankseckill.service.ISeckillProductService;
import com.example.bankseckill.utils.MD5Util;
import com.example.bankseckill.utils.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.function.ObjDoubleConsumer;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author liyangjing
 * @since 2022-01-26
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private ISeckillProductService seckillProductService;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ISeckillOrderService seckillOrderService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MQsender mQsender;
    /**
     * 生成秒杀订单
     * 多个sql操作 加入 事务处理
     * 加入redis处理
     * 为什么会超卖，因为读取数据从数据库太慢，当库存已经为0时，还有线程以为部位0
     * @param user
     * @param productVo
     * @return
     */
    @Override
    @Transactional
    public Boolean seckill(User user, ProductVo productVo) {
        //秒杀商品表减库存 查看秒杀id
        SeckillProduct seckillProduct = seckillProductService.getOne(new QueryWrapper<SeckillProduct>().
                eq("id", productVo.getPid()));
        seckillProduct.setStockCount(seckillProduct.getStockCount()-1);
        //更新秒杀产品的库存
        boolean seckillProductResult = seckillProductService.update(
                new UpdateWrapper<SeckillProduct>().setSql("stock_count = stock_count-1")
                        .eq("id", productVo.getPid()).gt("stock_count", 0));
        //如果更新失败则修改库存为0，不用创建订单。
//        if(seckillProduct.getStockCount()<1){
//            redisTemplate.opsForValue().set("isStockEmpty:"+productVo.getPid(),"0");
//        }
        //生成订单
        Order order = new Order();
        order.setUserId(user.getId());
        //普通产品订单
        order.setProductId((long) productVo.getId());
        order.setProductCount(1);
        //设置订单标题
        order.setProductName(productVo.getProductName());
        //秒杀价格默认1000
        order.setProductPrice(new BigDecimal(1000));
        //新建未支付
        order.setStatus(0);
        order.setCreatDate(new Date());
        int insert = orderMapper.insert(order);

        //生成秒杀订单
        SeckillOrder seckillOrder = new SeckillOrder();
        //获取订单id
        seckillOrder.setOrderId(order.getId());
        seckillOrder.setUserId(user.getId());
        seckillOrder.setProductId(new Long(productVo.getPid()));
        boolean save = seckillOrderService.save(seckillOrder);
        //缓存订单信息
        redisTemplate.opsForValue().set("order:"+user.getId()+":"+productVo.getPid(),seckillOrder);
        seckillOrder = seckillOrderService.findSecOrderById(seckillOrder.getId());
        //生成的订单
        mQsender.OrderDelayQueue(seckillOrder);
        //返回结果
        return save;
    }

    /**
     * 用户获取自己所有的订单
     * @param currentPage
     * @param size
     * @param user
     * @return
     */
    @Override
    public RespPageBean getOrdersByUserId(Integer currentPage, Integer size, User user) {
        //开启分页
        Page<Order> page = new Page<>(currentPage, size);
        IPage<Order> OrderIPage = orderMapper.getOrderByPage(page,user.getId());
        RespPageBean respPageBean = new RespPageBean(200,OrderIPage.getTotal(),OrderIPage.getRecords());
        return respPageBean;
    }

    /**
     * 创建秒杀地址
     * @param user
     * @param seckillProductId
     * @return
     */
    @Override
    public String createSecKillPath(User user, Long seckillProductId) {
        String PATH = MD5Util.md5(UUIDUtil.uuid() + "123456");
        redisTemplate.opsForValue().set("secKillPath:"+user.getId()+":"+seckillProductId,PATH,60, TimeUnit.SECONDS);
        return PATH;
    }

    /**
     * 校验秒杀地址
     * @param user
     * @param secproductId
     * @param path
     * @return
     */
    @Override
    public boolean checkSecPath(User user, Long secproductId, String path) {
        if (user == null || secproductId < 0 || StringUtils.isEmpty(path)) {
            return false;
        }
        String truepath = (String) redisTemplate.opsForValue().get("secKillPath:" + user.getId() + ":" + secproductId);
        return path.equals(truepath);
    }
}
